<!--
 * @title: 顶部 模糊检索 组件 (实现检索菜单) -- fuse不好用，直接使用数组filter方式过滤内容即可
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-30 23:13:05
 * @LastEditors: andy.ten@tom.com
 * @LastEditTime: 2022-06-06 11:24:32
 * @version: 1.0.3
 * @copyright: copyright (c) 2022 andyten
 *  node: you can not copy and/or use and/or modify this program free,
 *  please reserve the segment above.Please mail me if you have any question.
-->

<template>
  <div :class="{'show':show}" class="ht-header-search">
    <svg-icon class-name="search-icon" icon-class="search" @click.stop="handleClick" />
    <el-select
      ref="headerSearchSelect"
      v-model="search"
      filterable
      remote
      :remote-method="handleSearch"
      :loading="loading"
      default-first-option
      placeholder="全局检索..."
      class="header-search-select"
      @change="handleChange"
    >
      <!-- 如果是用fuse方式，注意改为option.item.path 结果集格式带item的key -->
      <el-option v-for="option in options" :key="option.path" :value="option" :label="option.title.join(' > ')" />
    </el-select>
  </div>
</template>

<script>
// import Fuse from 'fuse.js';
import path from 'path';

export default {
  name: 'HtHeaderSearch',
  data() {
    return {
      search: '',
      options: [],
      searchPool: [],
      show: false,
      fuse: undefined,
      loading: false
    };
  },
  computed: {
    routes() {
      return this.$store.getters.sidebarRoutes;
    },
    supportPinyinSearch() {
      return this.$store.state.settings.supportPinyinSearch;
    }
  },
  watch: {
    routes() {
      this.searchPool = this.generateRoutes(this.routes);
    },
    searchPool(list) {
      // 转换拼音
      if (this.supportPinyinSearch)
        this.addPinyinField(list);

      // this.initFuse(list);
    },
    show(value) {
      if (value)
        document.body.addEventListener('click', this.handleClose);
      else
        document.body.removeEventListener('click', this.handleClose);
    }
  },
  mounted() {
    this.searchPool = this.generateRoutes(this.routes);
  },
  methods: {
    async addPinyinField(list) {
      // console.log(list[0].pinyinTitle);
      if (list && list.length > 0)
        if (!list[0].pinyinTitle) {
          const pinyin = await require('@/components/HtPinyin');
          // console.log(pinyin);
          if (Array.isArray(list)) {
            list.forEach((element) => {
              const title = element.title;
              if (Array.isArray(title))
                title.forEach((v) => {
                  v = pinyin.getCamelChars(v).toLowerCase();
                  if (element.pinyinTitle)
                    element.pinyinTitle = v + ',' + element.pinyinTitle;
                  else
                    element.pinyinTitle = v;
                });
            });
            return list;
          }
        }
    },
    /**
     * @todo: 点击搜索放大镜响应方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-04-02 18:23:38
     */
    handleClick() {
      this.show = !this.show;
      if (this.show)
        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus();
    },
    /**
     * @todo: 点击其他位置触发搜索框关闭响应方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-04-02 18:24:27
     */
    handleClose() {
      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur();
      this.options = [];
      this.show = false;
    },
    /**
     * @todo: onchange事件 ，select框选中option后执行方法 跳转路由
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-04-02 17:23:56
     * @param {*} val
     */
    handleChange(val) {
      this.$router.push(val.path);
      this.search = '';
      this.options = [];
      this.$nextTick(() => {
        this.show = false;
      });
    },
    /**
     * @todo: fuse初始化 （不实用）
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-04-02 18:18:55
     * @param {*} list
     */
    // initFuse(list) {
    //   this.fuse = new Fuse(list, {
    //     shouldSort: true, // 是否按分数对结果列表排序
    //     threshold: 0.4, // 匹配算法阈值。阈值为0.0需要完全匹配（字母和位置），阈值为1.0将匹配任何内容。
    //     /**
    //      * 确定匹配与模糊位置（由位置指定）的距离。一个精确的字母匹配，即距离模糊位置很远的字符将被视为完全不匹配。
    //      * 距离为0要求匹配位于指定的准确位置，距离为1000则要求完全匹配位于使用阈值0.8找到的位置的800个字符以内。
    //      */
    //     location: 0, // 确定文本中预期找到的模式的大致位置。
    //     distance: 100,
    //     maxPatternLength: 32, // 模式的最大长度
    //     minMatchCharLength: 1, // 模式的最小字符长度
    //     keys: [{ // 搜索标题
    //       name: 'title',
    //       weight: 0.7
    //     }, { // 搜索拼音标题
    //       name: 'pinyinTitle',
    //       weight: 0.7
    //     }, {
    //       name: 'path', // 搜索路由path
    //       weight: 0.3
    //     }]
    //   });
    // },
    /**
     * @todo: 生成点击的路由option，过滤掉一级、二级路由
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-04-02 14:32:07
     * @param {*} routes
     * @param {*} basePath
     * @param {*} prefixTitle
     */
    generateRoutes(sidebarRoutes, basePath = '/', prefixTitle = []) {
      let res = [];
      for (const router of sidebarRoutes) {
        if (router.hidden) continue;
        const data = {
          path: path.resolve(basePath, router.path),
          title: [...prefixTitle]
        };
        if (router.meta && router.meta.title) {
          const i18ntitle = router.meta.title;
          // 将路由路径title都存入
          data.title = [...data.title, i18ntitle];
          // 过滤掉不可点击的路由
          if (router.redirect !== 'noredirect')
            res.push(data);
        }
        if (router.children) {
          const tempRoutes = this.generateRoutes(router.children, data.path, data.title);
          if (tempRoutes.length >= 1)
            res = [...res, ...tempRoutes];
        }
      }
      return res;
    },
    /**
     * @todo: 模糊检索方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-04-02 17:20:39
     * @param {*} query 输入的检索内容
     */
    handleSearch(query) {
      if (query !== '')
        // this.options = this.fuse.search(query);
        // console.log(JSON.stringify(this.searchPool));
        if (Array.isArray(this.searchPool))
          this.options = this.searchPool.filter((item) => {
            if (item.title.join('').indexOf(query) !== -1)
              return item;
            else if (item.pinyinTitle.indexOf(query.toLowerCase()) !== -1)
              return item;
            else if (item.path.indexOf(query) !== -1)
              return item;
          });
        else
          this.options = [];
      else
        this.options = [];
    }
  }
};
</script>

<style lang="scss" scoped>
.ht-header-search {
  font-size: 0 !important;

  .search-icon {
    font-size: 18px;
    vertical-align: middle;
    cursor: pointer;
  }

  .header-search-select {
    display: inline-block;
    width: 0;
    overflow: hidden;
    font-size: 18px;
    vertical-align: middle;
    background: transparent;
    border-radius: 0;
    transition: width 0.2s;

    ::v-deep .el-input__inner {
      padding-right: 0;
      padding-left: 0;
      vertical-align: middle;
      border: 0;
      border-bottom: 1px solid #d9d9d9;
      border-radius: 0;
      box-shadow: none !important;
    }
  }

  &.show {
    .header-search-select {
      width: 210px;
      margin-left: 10px;
    }
  }
}
</style>
